﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "odbc_fields.h"

namespace xos_odbc
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    static odbc_fields::POOL * pool_ptr = 0;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    odbc_fields::odbc_fields()
    {
        init_data();
    }

    odbc_fields::~odbc_fields()
    {
        term();
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // public method

    int odbc_fields::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // public method

    int odbc_fields::set_connect( i_dbc * lpConnect )
    {
        int ret = 0;
        m_pConnect = lpConnect;
        return ret;
    }

    int odbc_fields::init_data()
    {
        int ret = 0;

        m_table_name = "";
        m_sql = "";

        m_pConnect = 0;
        m_pStmt = 0;

        m_pKey = 0;

        return ret;
    }

    int odbc_fields::init()
    {
        int ret = 0;
        return ret;
    }

    int odbc_fields::term()
    {
        int ret = 0;

        xos_stl::release_interface( m_pStmt );
        field_list.put_back_to_pool( true );

        init_data();

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // i_fields method

    // 
    // 添加整数字段
    // 
    int odbc_fields::push( const char * lpszName, xos::xos_i32 * lpData, bool bIsKey )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_I32;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( xos::xos_i32 );
            pF->i32_ptr = lpData;
            pF->m_bIsKey = bIsKey;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加短整数字段
    // 
    int odbc_fields::push( const char * lpszName, xos::xos_i64 * lpData )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_I64;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( xos::xos_i64 );
            pF->i64_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加短整数字段
    // 
    int odbc_fields::push( const char * lpszName, xos::xos_i16 * lpData )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_I16;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( xos::xos_i16 );
            pF->i16_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加字节字段
    // 
    int odbc_fields::push( const char * lpszName, xos::xos_i8 * lpData )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_I8;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( xos::xos_i8 );
            pF->i8_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加整数字段
    // 
    int odbc_fields::push( const char * lpszName, xos::xos_u32 * lpData, bool bIsKey )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_U32;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( xos::xos_u32 );
            pF->u32_ptr = lpData;
            pF->m_bIsKey = bIsKey;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加短整数字段
    // 
    int odbc_fields::push( const char * lpszName, xos::xos_u64 * lpData )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_U64;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( xos::xos_u64 );
            pF->u64_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加短整数字段
    // 
    int odbc_fields::push( const char * lpszName, xos::xos_u16 * lpData )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_U16;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( xos::xos_u16 );
            pF->u16_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加字节字段
    // 
    int odbc_fields::push( const char * lpszName, xos::xos_u8 * lpData )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_U8;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( xos::xos_u8 );
            pF->u8_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加bool字段
    // 
    int odbc_fields::push( const char * lpszName, bool * lpData )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_BOOL;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( bool );
            pF->bool_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加字串字段
    // 
    int odbc_fields::push( const char * lpszName, char * lpData, int nBufSize )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_CHAR_ARRAY;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = nBufSize;
            pF->char_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加float字段
    // 
    int odbc_fields::push( const char * lpszName, float * lpData, int nDigitNum )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_FLOAT;
            pF->m_nDigitnum = nDigitNum;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( float );
            pF->float_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    // 
    // 添加double字段
    // 
    int odbc_fields::push( const char * lpszName, double * lpData, int nDigitNum )
    {
        int ret = 0;

        odbc_field * pF = 0;

        if( 0 == ret )
        {
            pF = odbc_field::get_item_from_pool( true );
            pF->init();
            pF->m_eType = i_stmt::VT_DOUBLE;
            pF->m_nDigitnum = nDigitNum;
            pF->m_name = lpszName;
            pF->m_nIndex = ( int )field_list.size();
            pF->m_nBufSize = sizeof( double );
            pF->double_ptr = lpData;
        }

        if( 0 == ret )
        {
            field_list.push_back( pF );
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // 设置为更改过
    // 
    int odbc_fields::set_dirty( const char * lpszName )
    {
        int ret = 0;

        odbc_field * pF = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field * pField = *iter;
            if( pField->m_name == lpszName )
            {
                pF = pField;
                break;
            }
        }

        if( ( 0 == ret ) && pF )
        {
            pF->m_bDirty = true;
        }

        return ret;
    }

    // 
    // 设置为更改过
    // 
    int odbc_fields::set_dirty( int nIndex )
    {
        int ret = 0;

        odbc_field * pF = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field * pField = *iter;
            if( pField->m_nIndex == nIndex )
            {
                pF = pField;
                break;
            }
        }

        if( ( 0 == ret ) && pF )
        {
            pF->m_bDirty = true;
        }

        return ret;
    }

    // 
    // 设置为更改过
    // 
    int odbc_fields::set_all_dirty()
    {
        int ret = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field * pF = *iter;
            pF->m_bDirty = true;
        }

        return ret;
    }

    // 
    // 恢复为没改过
    // 
    int odbc_fields::clear_dirty( const char * lpszName )
    {
        int ret = 0;

        odbc_field * pF = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field * pField = *iter;
            if( pField->m_name == lpszName )
            {
                pF = pField;
                break;
            }
        }

        if( ( 0 == ret ) && pF )
        {
            pF->m_bDirty = false;
        }

        return ret;
    }

    // 
    // 恢复为没改过
    // 
    int odbc_fields::clear_dirty( int nIndex )
    {
        int ret = 0;

        odbc_field * pF = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field * pField = *iter;
            if( pField->m_nIndex == nIndex )
            {
                pF = pField;
                break;
            }
        }

        if( ( 0 == ret ) && pF )
        {
            pF->m_bDirty = false;
        }

        return ret;
    }

    // 
    // 恢复为没改过
    // 
    int odbc_fields::clear_all_dirty()
    {
        int ret = 0;

        for( odbc_field::ITER iter = field_list.begin(); ( 0 == ret ) && ( iter != field_list.end() ); ++iter )
        {
            odbc_field * pF = *iter;
            pF->m_bDirty = false;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // 设置表名
    // 
    int odbc_fields::set_table_name( const char * lpszTableName )
    {
        int ret = 0;
        m_table_name = lpszTableName;
        return ret;
    }

    //
    // 编译sql
    // 
    //  0 : success. 
    //  1 : running. 
    // -1 : failed
    // 
    int odbc_fields::prepare_sql()
    {
        return m_pStmt->prepare_sql( m_sql.c_str() );
    }

    // 
    //  0 : success. 
    //  1 : running. 
    // -1 : failed
    int odbc_fields::execute()
    {
        int ret = 0;

        if( ( 0 == ret ) && !m_pStmt )
        {
            ret = -1;
        }

        if( 0 == ret )
        {
            ret = m_pStmt->execute();
        }

        return ret;
    }

    // 
    // 清除查询结果
    // 
    int odbc_fields::clear()
    {
        int ret = 0;
        xos_stl::release_interface( m_pStmt );
        return ret;
    }

    // 
    //  0 : success
    //  1 : pending
    //  2 : no data
    // -1 : failed
    // 
    int odbc_fields::fetch()
    {
        int ret = 0;

        for( odbc_field::ITER iter = field_list.begin(); iter != field_list.end(); ++iter )
        {
            odbc_field * pF = *iter;
            pF->clear_value();
        }

        if( ( 0 == ret ) && !m_pStmt )
        {
            ret = -1;
        }

        if( 0 == ret )
        {
            ret = m_pStmt->fetch();
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // SELECT follow_id, topic_id, user_id FROM follow
    // 
    // lpszSql说明：
    // 
    //  not null : where子句。如：where id = 1
    //      null : 全表查询
    // 
    int odbc_fields::prepare_query( const char * lpszSql )
    {
        int ret = 0;

        std::string sql = "SELECT ";
        i_stmt * pStmt = 0;

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            while( iter != field_list.end() )
            {
                odbc_field * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    m_pKey = pF;
                }
                sql += pF->m_name;
                if( iter != field_list.end() )
                {
                    sql += ", ";
                }
            }
            sql += " FROM " + m_table_name;
        }

        if( ( 0 == ret ) && lpszSql )
        {
            sql += " ";
            sql += lpszSql;
        }

        if( 0 == ret )
        {
            ret = m_pConnect->create_stmt( &pStmt );
        }

        if( 0 == ret )
        {
            xos_stl::release_interface( m_pStmt );
            m_pStmt = pStmt;
            m_sql = sql;
            pStmt = 0;
        }

        xos_stl::release_interface( pStmt );

        return ret;
    }

    int odbc_fields::bind_query()
    {
        int ret = 0;

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            while( iter != field_list.end() )
            {
                odbc_field * pF = *iter++;
                pF->bind_col( m_pStmt );
            }
        }

        return ret;
    }

    // 
    // UPDATE follow SET topic_id = ?, user_id = ? WHERE follow_id = ?
    // 修改
    // 
    int odbc_fields::prepare_update()
    {
        int ret = 0;

        std::string sql = "UPDATE " + m_table_name + " SET ";
        odbc_field * pKey = 0;
        i_stmt * pStmt = 0;

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            bool bIsFirst = true;
            while( iter != field_list.end() )
            {
                odbc_field * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    m_pKey = pF;
                    pKey = pF;
                    continue;
                }
                if( !pF->m_bDirty )
                {
                    continue;
                }
                if( bIsFirst )
                {
                    bIsFirst = false;
                }
                else
                {
                    sql += ", ";
                }
                sql += pF->m_name + " = ?";
            }
            if( !pKey )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            char v[256] = { 0 };
            g_pSysData->m_pContainer->crt()->sprintf( v, sizeof( v ), " WHERE %s = %d", pKey->m_name.c_str(), *pKey->i32_ptr );
            sql += v;
        }

        if( 0 == ret )
        {
            ret = m_pConnect->create_stmt( &pStmt );
        }

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            int nIndex = 0;
            while( iter != field_list.end() )
            {
                odbc_field * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    pKey = pF;
                    continue;
                }
                if( !pF->m_bDirty )
                {
                    continue;
                }
                int nOld = pF->m_nIndex;
                pF->m_nIndex = nIndex++;
                pF->bind_param( pStmt );
                pF->m_nIndex = nOld;
            }
        }

        if( 0 == ret )
        {
            xos_stl::release_interface( m_pStmt );
            m_pStmt = pStmt;
            m_sql = sql;
            pStmt = 0;
        }

        xos_stl::release_interface( pStmt );

        return ret;
    }

    // 
    // "INSERT INTO follow ( topic_id, user_id, content, modify_time, create_time, read_auth, write_auth, del_auth ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )"
    // 添加
    // 
    // declare @t table (id int); 
    // INSERT INTO tb_test( name, opt_dtm, size ) OUTPUT INSERTED.id INTO @t VALUES( ?, ?, ? );
    // SELECT id FROM @t;
    // 
    int odbc_fields::prepare_add()
    {
        int ret = 0;

        std::string sql = "INSERT INTO " + m_table_name + "( ";
        odbc_field * pKey = 0;
        i_stmt * pStmt = 0;

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            std::string values = " VALUES ( ";
            bool bIsFirst = true;

            while( iter != field_list.end() )
            {
                odbc_field * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    m_pKey = pF;
                    pKey = pF;
                    continue;
                }
                if( !pF->m_bDirty )
                {
                    continue;
                }
                if( bIsFirst )
                {
                    bIsFirst = false;
                }
                else
                {
                    values += ", ";
                    sql += ", ";
                }
                sql += pF->m_name;
                values += "?";
            }

            if( !bIsFirst )
            {
                values += " )";
                sql += " )";
            }

            sql += values;
        }

        if( 0 == ret )
        {
            ret = m_pConnect->create_stmt( &pStmt );
        }

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            int nIndex = 0;
            while( iter != field_list.end() )
            {
                odbc_field * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    continue;
                }
                if( !pF->m_bDirty )
                {
                    continue;
                }
                int nTemp = pF->m_nIndex;
                pF->m_nIndex = nIndex++;
                pF->bind_param( pStmt );
                pF->m_nIndex = nTemp;
            }
        }

        if( 0 == ret )
        {
            xos_stl::release_interface( m_pStmt );
            m_pStmt = pStmt;
            m_sql = sql;
            pStmt = 0;
        }

        xos_stl::release_interface( pStmt );

        return ret;
    }

    // 
    // DELETE FROM follow WHERE follow_id = %d
    // 删除
    // 
    int odbc_fields::prepare_del()
    {
        int ret = 0;

        std::string sql = "DELETE FROM " + m_table_name + " WHERE ";
        odbc_field * pKey = 0;
        i_stmt * pStmt = 0;

        if( 0 == ret )
        {
            odbc_field::ITER iter = field_list.begin();
            while( iter != field_list.end() )
            {
                odbc_field * pF = *iter++;
                if( pF->m_bIsKey )
                {
                    m_pKey = pF;
                    pKey = pF;
                    break;
                }
            }
            if( !pKey )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            char v[256] = { 0 };
            g_pSysData->m_pContainer->crt()->sprintf( v, sizeof( v ), "%s = %d", pKey->m_name.c_str(), *pKey->i32_ptr );
            sql += v;
        }

        if( 0 == ret )
        {
            ret = m_pConnect->create_stmt( &pStmt );
        }

        if( 0 == ret )
        {
            m_pStmt = pStmt;
            m_sql = sql;
            pStmt = 0;
        }

        xos_stl::release_interface( pStmt );

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    // 
    // 帮助方法
    // 
    int odbc_fields::set_id( xos::xos_i32 id )
    {
        int ret = 0;
        if( m_pKey )
        {
            *m_pKey->i32_ptr = id;
        }
        return ret;
    }

    const char * odbc_fields::sql()
    {
        return m_sql.c_str();
    }

} // xos_odbc
